using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using RoboTrocity.Code.ObjectStates;
using RoboTrocity.Code.Props;

namespace RoboTrocity {
	abstract class GameObject {

		static int id = 0;
		
		private readonly int thisID;
		protected Point position;
		private int height, width;
		protected ObjectState currentState;
		protected List<ObjectState> stateList;



        protected GameObject() : this(Point.Zero) { }

        protected GameObject(Point _position) : this(_position, "brick") { }

		protected GameObject(Point _position, string imgLoc) {
			thisID = id++;
			position = _position;
			stateList = new List<ObjectState>();
			currentState = new GeneralState(new Sprite(imgLoc));
			Height = 50;
			Width = 50;
		}

		public abstract void Update(float timeElapsed);
        
		public void setPositionX(int _positionX) {
			position.X = _positionX;
		}
		public void setPositionY(int _positionY) {
			position.Y = _positionY;
		}

		public virtual void Draw(SpriteBatch sBatch, Camera camera) {
			if (Bounds.Right >= camera.Bounds.Left && Bounds.Left <= camera.Bounds.Right) {
				DispSprite.DrawFrame(sBatch, 
						new Rectangle(Position.X - camera.Origin.X, Position.Y - camera.Origin.Y, Width, Height), 
						ObjectDepth, 
						false);
			}
		}

		public void addState(ObjectState state) {
			if (stateList.Count == 0) {
				currentState = state;
			}
			//check that there's nothing of the same state first
			for (int i = 0; i < stateList.Count; i++) {
				if (stateList[i].GetType() == state.GetType()) {
					stateList[i] = state;
					return;
				}
			}
			stateList.Add(state);
		}

		public ObjectState getState(Type stateType) {
			foreach (ObjectState oState in stateList) {
				if (oState.GetType() == stateType) {
					return oState;
				}
			}
			//nothing to return
			return null;
		}

		#region Collision Functions
		public virtual void collideWith(GameObject gameObject) {
			if (gameObject is Terrain) {
				collideWith((Terrain)gameObject);
			} else if (gameObject is Bullet) {
				collideWith((Bullet)gameObject);
			} else if (gameObject is Enemy) {
				collideWith((Enemy)gameObject);
			} else if (gameObject is Player) {
				collideWith((Player)gameObject);
			}
		}		
		public virtual void collideWith(Terrain terrain) { }
		public virtual void collideWith(Bullet bullet) { }
		public virtual void collideWith(Entity entity) { }
		public virtual void collideWith(Player player) { }
		public virtual void collideWith(Enemy enemy) { }
		public virtual void collideWith(Prop prop) {}

		#endregion


		#region Fields
		/// <summary>
		/// Returns the upper-left corner of the GameObject.
		/// </summary>
		public Point Position {
			get { return position; }
			set { position = value; }
		}

		/// <summary>
		/// Returns the Sprite.
		/// </summary>
		public virtual Sprite DispSprite {
			get { return currentState.StateSprite; }
			//set { this.dispSprite = value; }
		}

		/// <summary>
		/// Returns the current ObjectState.
		/// </summary>
		public virtual ObjectState CurrentState {
			get { return currentState; }
			set { currentState = value; }
		}

		/// <summary>
		/// Gets the CollisionBox surrounding the GameObject's Sprite.
		/// </summary>
		public virtual CollisionBox Bounds {
			get { return new CollisionBox(position.X, position.Y, Width, Height); }
		}

		/// <summary>
		/// Returns the point at (Height, Width/2).
		/// </summary>
		public Point BottomCenter {
			get { return new Point((Position.X + Width / 2), Bounds.Bottom); }
		}

		/// <summary>
		/// Returns the unique id of the GameObject
		/// </summary>
		public int ID {
			get { return thisID; }
		}

		/// <summary>
		/// Returns the z depth of the GameObject
		/// </summary>
		public virtual float ObjectDepth {
			get { return 0.5f; }
		}

		/// <summary>
		/// Returns the center of the GameObject.
		/// </summary>
		public Point Center {
			get { return new Point(Position.X + Width / 2, position.Y + Height / 2); }
		}

		/// <summary>
		/// Returns the string representing the object in XML.
		/// </summary>
		public virtual string MapXMLData {
			get { return ""; }
		}

		/// <summary>
		/// Returns the height of the GameObject.
		/// </summary>
		public int Height {
			get { return height;}
			set { height = value; }
		}

		/// <summary>
		/// Returns the width of the GameObject.
		/// </summary>
		public int Width {
			get { return width; }
			set { width = value; }
		}

		public List<ObjectState> StateList {
			get { return stateList; }
		}

		#endregion
	}
}